#!/usr/bin/env python3
# NOTE: PYTHONUNBUFFERED is set in the entrypoint for unbuffered output
#
# Publish an oscontainer as the machine-os-content in an OpenShift release
# series
"""
Example usage:
    cosa release-ocp \
        --to-url horcux.dev/rhcos/rhcos-ocp-test \
        --authfile auth.json \
        --fetch-bin
"""

import argparse
import json
import logging as log
import os
import sys


COSA_PATH = os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0, COSA_PATH)
from cosalib.meta import GenericBuildMeta as Meta
from cosalib.cmdlib import (
    get_basearch,
    runcmd
)

os.environ["PATH"] = f"{os.getcwd()}:{COSA_PATH}:{os.environ.get('PATH')}"
OCP_SERVER = "https://api.ci.openshift.org"
OCP_RELEASE_STREAM = "quay.io/openshift-release-dev/ocp-release"

log.basicConfig(
    format='[%(levelname)s]: %(message)s',
    level=log.INFO)


def ocp_versions(meta):
    """
    Return the corresponding OCP version.
    RHCOS is versioned <OCP MAJ><OCP MIN>.<RHEL MAJ><RHEL MIN>.
    For example OCP version 4.6 with RHEL 8.1 would be 46.81
    """

    if "OpenShift" not in meta.get("summary", None):
        return None, None
    ostree_v = meta.get("ostree-version").split('.')
    ocp_major, ocp_minor = list(ostree_v[0])
    os_major, os_minor = list(ostree_v[1])
    return (f"{ocp_major}.{ocp_minor}", f"{os_major}.{os_minor}")


def release_stream(meta, args, ocp_ver):
    """
    Locate the release version based on the release streams.
    If 'latest' look for the latest Z in the OCP series
    """
    if args.from_tag != "latest":
        return args.from_tag

    tag_cmd = ["skopeo", "list-tags"]
    if args.authfile != "":
        tag_cmd.extend(["--authfile", args.authfile])
    tag_cmd.extend([f"docker://{args.from_url}"])
    tags = json.loads(runcmd(tag_cmd, capture_output=True).stdout)

    log.info(f"Looking for latest release tag for {ocp_ver}")
    ctags = []
    for tag in tags["Tags"]:
        if ocp_ver in tag and args.arch in tag:
            ctags.append(tag)
    sctags = sorted(ctags)
    log.info(f"Generating release payload from tag {sctags[-1]}")
    return f"{args.from_url}:{sctags[-1]}"


if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('--workdir', default=os.getcwd())
    parser.add_argument('--build', default='latest')
    parser.add_argument('--schema', help='location of meta.json schema',
                        default=os.environ.get("COSA_META_SCHEMA",
                                               f'{COSA_PATH}/v1.json'))
    parser.add_argument("--authfile", action="store", required=True,
                        help="Pull secret")
    parser.add_argument("--arch", action='store',
                        default=get_basearch(),
                        help="Architecture to use")
    parser.add_argument("--from-url", action='store',
                        default=OCP_RELEASE_STREAM)
    parser.add_argument("--from-tag", action="store",
                        default="latest",
                        help="version to base release on; latest means latest in z stream")
    parser.add_argument("--to-url", action='store', required=True)
    parser.add_argument("--to-tag", action="store", default=None,
                        help="release tag to use")
    parser.add_argument('--content', action="store",
                        default="machine-os-content",
                        help="type release payload image")
    parser.add_argument('--server', action="store",
                        default=OCP_SERVER,
                        help="server to get releases from")
    parser.add_argument('--oc-bin', action="store", default="oc",
                        help="Openshift ocp binary")
    parser.add_argument("--dry-run", default=False, action='store_true')

    args = parser.parse_args()

    meta = Meta(args.workdir, args.build, schema=args.schema)
    oscontainer = meta.get("oscontainer")
    if oscontainer is None:
        raise Exception("oscontainer was not found in meta.json")

    to_tag = args.to_tag
    if to_tag is None:
        to_tag = f"{meta['name']}-{meta.get('buildid')}"

    ocp_ver, os_ver = ocp_versions(meta)
    log.info(f"Generating payload for {ocp_ver} for OS Version {os_ver}")
    from_release = release_stream(meta, args, ocp_ver)

    cmd = [args.oc_bin, "adm", "release", "new", "-a", args.authfile]
    if ocp_ver:
        cmd.extend(["-n", "ocp"])

    payload_dest = f"{args.to_url}:{to_tag}"
    cmd.extend([
        "--from-release", from_release,
        "--to-image", payload_dest,
        f"{args.content}={oscontainer['image']}@{oscontainer['digest']}"
    ])

    log.info(f"Command: {' '.join(cmd)}")
    if not args.dry_run:
        runcmd(cmd)
        log.info(f"Payload released to: {payload_dest}")
